#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>
using namespace std;

template <class T>
class BlockQueue
{
    static const int defalutnum = 5;//队列的大小
public:
    BlockQueue(int maxcap = defalutnum):maxcap_(maxcap)
    {
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&c_cond_, nullptr);
        pthread_cond_init(&p_cond_, nullptr);
    }

    //出队-消费者
    T pop()
    {
        pthread_mutex_lock(&mutex_);
        while(q_.size() == 0) 
        {
            pthread_cond_wait(&c_cond_, &mutex_); //场所为空则消费者必须等待
        }
        
        T out = q_.front(); 
        q_.pop();//消费了一个数据
        pthread_cond_signal(&p_cond_); //唤醒生产者
        pthread_mutex_unlock(&mutex_);

        return out;
    }

    //入队-生产者
    void push(const T &in)
    {
        pthread_mutex_lock(&mutex_);
        while(q_.size() == maxcap_)
        { 
            pthread_cond_wait(&p_cond_, &mutex_); //场所为满则生产者必须等待
        }
        // 1. 队列没满 2.被唤醒 
        q_.push(in);//生产了一个数据                
        pthread_cond_signal(&c_cond_);//唤醒消费者
        pthread_mutex_unlock(&mutex_);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&c_cond_);
        pthread_cond_destroy(&p_cond_);
    }
private:
    std::queue<T> q_; // 复用容器队列
    int maxcap_;      // 队列大小
    pthread_mutex_t mutex_;//生产者和消费者共用一把锁，因为他们的互斥的
    pthread_cond_t c_cond_;//消费者的等待队列
    pthread_cond_t p_cond_;//生产者的等待队列
};